#include "StdAfx.h"
#include "TsVanillaOptionPricer.h"
#include "OptionUtils.h"

#include <exception>
#include <vector>

namespace TreasAlgo
{

TsVanillaOptionPricer::TsVanillaOptionPricer()
{
}


TsVanillaOptionPricer::~TsVanillaOptionPricer()
{
}

void TsVanillaOptionPricer::priceOptionEuro(
	Date		valueDate,
	Date		maturity,
	Real		underlying,
	Real		strike,
	Rate		riskFreeRate,
	Spread		dividendYield,
	Volatility	volatility,
	double		&NPV,
	double		&delta,
	double		&gamma,
	double		&theta)
{
	// Hard-coded values for now
	Calendar calendar = TARGET();
	DayCounter dayCounter = Actual365Fixed();
	Option::Type type(Option::Call);
	Date settlementDate = valueDate;

	// Exercise type
    Handle<Quote> underlyingH(
        boost::shared_ptr<Quote>(new SimpleQuote(underlying)));

    // bootstrap the yield/dividend/vol curves
	// Flat yield structure
    Handle<YieldTermStructure> flatTermStructure(
        boost::shared_ptr<YieldTermStructure>(
            new FlatForward(settlementDate, riskFreeRate, dayCounter)));

	// Flat dividend
    Handle<YieldTermStructure> flatDividendTS(
        boost::shared_ptr<YieldTermStructure>(
            new FlatForward(settlementDate, dividendYield, dayCounter)));

	// Flat vol
    Handle<BlackVolTermStructure> flatVolTS(
        boost::shared_ptr<BlackVolTermStructure>(
            new BlackConstantVol(settlementDate, calendar, volatility, dayCounter)));

    boost::shared_ptr<StrikedTypePayoff> payoff(
                                    new PlainVanillaPayoff(type, strike));
	
	// BSM process
    boost::shared_ptr<BlackScholesMertonProcess> bsmProcess(
                new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS));

	boost::shared_ptr<Exercise> europeanExercise(
                            new EuropeanExercise(maturity));

	VanillaOption europeanOption(payoff, europeanExercise);
    
	Size timeSteps = TsOptionUtils::getNumTimeSteps(valueDate, maturity);
	europeanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(new FdBlackScholesVanillaEngine(bsmProcess, 
																									 timeSteps, 
																									 timeSteps - 1)));
				
	NPV = europeanOption.NPV();
	delta = europeanOption.delta();
	gamma = europeanOption.gamma();
	theta = europeanOption.theta();
}

void TsVanillaOptionPricer::priceOptionAmer(
	Date		valueDate,
	Date		maturity,
	Real		underlying,
	Real		strike,
	Rate		riskFreeRate,
	Spread		dividendYield,
	Volatility	volatility,
	double		&NPV,
	double		&delta,
	double		&gamma)
{
	// Hard-coded values for now
	Calendar calendar = TARGET();
	DayCounter dayCounter = Actual365Fixed();
	Option::Type type(Option::Call);
	Date settlementDate = valueDate;

	// Exercise type
    Handle<Quote> underlyingH(
        boost::shared_ptr<Quote>(new SimpleQuote(underlying)));

    // bootstrap the yield/dividend/vol curves
	// Flat yield structure
    Handle<YieldTermStructure> flatTermStructure(
        boost::shared_ptr<YieldTermStructure>(
            new FlatForward(settlementDate, riskFreeRate, dayCounter)));

	// Flat dividend
    Handle<YieldTermStructure> flatDividendTS(
        boost::shared_ptr<YieldTermStructure>(
            new FlatForward(settlementDate, dividendYield, dayCounter)));

	// Flat vol
    Handle<BlackVolTermStructure> flatVolTS(
        boost::shared_ptr<BlackVolTermStructure>(
            new BlackConstantVol(settlementDate, calendar, volatility, dayCounter)));

    boost::shared_ptr<StrikedTypePayoff> payoff(
                                    new PlainVanillaPayoff(type, strike));
	
	// BSM process
    boost::shared_ptr<BlackScholesMertonProcess> bsmProcess(
                new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS));

    boost::shared_ptr<Exercise> americanExercise(
                                        new AmericanExercise(settlementDate,
                                                            maturity));

	VanillaOption americanOption(payoff, americanExercise);
    
	Size timeSteps = TsOptionUtils::getNumTimeSteps(valueDate, maturity);
	americanOption.setPricingEngine(boost::shared_ptr<PricingEngine>(new FdBlackScholesVanillaEngine(bsmProcess, 
																									 timeSteps, 
																									 timeSteps - 1)));
				
	NPV = americanOption.NPV();
	delta = americanOption.delta();
	gamma = americanOption.gamma();
}
}